42장 비동기 프로그래밍


동기 처리와 비동기 처리

자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택을 갖는다. 이말인 즉슨, 여러 함수를 동시에 실행할 수가 없고 실행중인 실행 컨텍스트 를 제외한 모든 실행 컨텍스트는 대기 중인 태스크 들이다.

이렇게 한번에 하나의 태스크만 실행할 수 있는 방식을 싱글 스레드 라고 한다. 싱글 스레드 방식에서 오래 걸리는 태스크를 실행하는 경우 블로킹이 발생한다.

setTimeout 처럼 작동하는 sleep을 구현해보자

// sleep 함수는 일정 시간(delay)이 경과한 이후에 콜백 함수(func)를 호출한다.
function sleep(func, delay) {
  // Date.now()는 현재 시간을 숫자(ms)로 반환한다.("30.2.1. Date.now" 참고)
  const delayUntil = Date.now() + delay;

  // 현재 시간(Date.now())에 delay를 더한 delayUntil이 현재 시간보다 작으면 계속 반복한다.
  while (Date.now() < delayUntil);
  // 일정 시간(delay)이 경과한 이후에 콜백 함수(func)를 호출한다.
  func();
}

function foo() {
  console.log('foo');
}

function bar() {
  console.log('bar');
}

// sleep 함수는 3초 이상 실행된다..
sleep(foo, 3 * 1000);
// bar 함수는 sleep 함수의 실행이 종료된 이후에 호출되므로 3초 이상 블로킹된다.
bar();
// (3초 경과 후) foo 호출 -> bar 호출

sleep 하는 동안 뒤의 작업들이 blocking 된다.
이렇게 실행 중인 태스크가 종료할 때까지 대기하는 방식을 동기 처리라고 한다.
실행 순서가 보장되지만 뒤에 애들이 블로킹 된다.

Untitled 36.png|Untitled 36.png

setTimeout 사용하는 경우

function foo() {
  console.log('foo');
}

function bar() {
  console.log('bar');
}

// 타이머 함수 setTimeout은 일정 시간이 경과한 이후에 콜백 함수 foo를 호출한다.
// 타이머 함수 setTimeout은 bar 함수를 블로킹하지 않는다.
setTimeout(foo, 3 * 1000);
bar();
// bar 호출 -> (3초 경과 후) foo 호출

setTimeout도 delay 이후에 foo가 실행되지만 그 사이에 다른 작업들이 블로킹 되지 않고 실행된다.
이런 방식을 비동기 처리 라고 한다.

Untitled 1 22.png|Untitled 1 22.png

블로킹이 발생하지는 않지만, 태스크의 실행 순서가 보장되지 않음.
타이머 함수인 setTimeout과 setInterval, HTTP 요청, 이벤트 핸들러는 비동기 처리 방식으로 동작한다.

이벤트 루프와 태스크 큐

Untitled 2 18.png|Untitled 2 18.png

콜 스택과 힙으로 구성된 자바스크립트 엔진은 태스크가 요청되면 콜 스택을 통해 요청된 작업을 순차적으로 실행할 뿐이다.

비동기 처리에서 소스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트 엔진을 구동하는 환경인 브라우저 또는 node.js 가 담당한다.

브라우저는 태스크 큐와 이벤트 루프를 제공

function foo() {
  console.log('foo');
}

function bar() {
  console.log('bar');
}

setTimeout(foo, 0); // 0초(실제는 4ms) 후에 foo 함수가 호출된다.
bar();
  1. 전역 코드평가. 전역 실행 컨텍스트 생성되어 콜 스택에 푸쉬
  2. setTimeout 함수 호출. 함수 실행 컨텍스트 생성되어 콜스택에 푸쉬.
  3. 콜백함수 스케줄링하고 종료되어 콜스택에서 pop
  4. 브라우저 최소 지연시간인 4ms 있다가 foo를 태스크 큐에 push
    그 와중에 bar 함수 호출되서 실행컨텍스트 생성되서 콜 스택에 push
  5. 전역 코드 실행 종료되면 전역 실행 컨텍스트가 콜 스택에서 pop
  6. 콜 스택에 아무것도 없으니까 대기중인 foo가 콜스택에 push

싱글 스레드 방식으로 동작하는 건 브라우저가 아니라 내장된 자바스크립트 엔진이다.

애초에 브라우저가 싱글 스레드 였으면, 비동기 동작을 수행할 수도 없었다. 즉, 브라우저는 멀티 스레드로 동작.

reference